package com.example.qxfw.slhx.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dmgis.entity.*;
import com.example.qxfw.common.entity.zy.BaseProduct;
import com.example.qxfw.common.entity.zy.HxyjWarning;
import com.example.qxfw.common.service.impl.FileRequestService;
import com.example.qxfw.common.util.DmgisUtils;
import com.example.qxfw.slhx.mapper.HxyjWarningMapper;
import com.example.qxfw.slhx.service.HxybService;
import com.example.qxfw.mongodb.hy.entity.HyDocFile;
import com.example.qxfw.shfx.dto.ColorAndNameDto;
import com.example.qxfw.shfx.entity.ColorAndPos;
import com.example.qxfw.ybzz.mapper.BaseProductMapper;
import com.example.qxfw.yjqx.dto.LayerRcoDto;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

import static com.example.qxfw.common.util.DmgisUtils.getColorAndNameMap;
import static com.example.qxfw.common.util.DmgisUtils.getCountryMap;
import static com.example.qxfw.common.util.DocxUtil.*;
import static com.example.qxfw.common.util.DocxUtil.setCellLocation;
import static com.example.qxfw.common.util.LayerUtil.getLayerClass;

@Service
public class HxybServiceImpl implements HxybService {

    @Value("${dmgis.ip}")
    private String dmgisIp;

    @Value("${dmgis.port}")
    private String dmgisPort;

    @Value("${dmgis.serName}")
    private String dmgisSerName;

    @Value("${filePath.resourcePath}")
    private String resourcePath;

    @Value("${filePath.active}")
    private String active;

    @Autowired
    private HxyjWarningMapper hxyjWarningMapper;

    @Autowired
    private BaseProductMapper baseProductMapper;


    @Qualifier("mongoSecondTemplate")
    @Autowired
    private MongoTemplate mongoTemplate;

    FileRequestService ms = new FileRequestService();

    @Override
    public int insertOfHxybWaring(String pos, int state) {
        String[] sections = pos.split("\\*");
        StringBuilder sb = new StringBuilder();
        for (String section : sections) {
            String[] parts = section.split("#");
            String coordinates = parts[1].trim();
            String[] xyPairs = coordinates.split(",");
            List<DmMapPoint> lbtPoints = new ArrayList<>();
            for (String xyPair : xyPairs) {
                String[] xy = xyPair.trim().split("\\s+");
                double lon = Double.parseDouble(xy[0]);
                double lat = Double.parseDouble(xy[1]);
                DmMapPoint lbtPoint = DmgisUtils.wgsToLbt(lon, lat);
                lbtPoints.add(lbtPoint);
            }
            sb.append(parts[0]).append("#");
            for (DmMapPoint lbtPoint : lbtPoints) {
                sb.append(lbtPoint.getX()).append(" ").append(lbtPoint.getY()).append(",");
            }
            sb.setLength(sb.length() - 1);
            sb.append("*");
        }
        HxyjWarning hxyjWarning = new HxyjWarning();
        hxyjWarning.setPos(sb.toString());
        hxyjWarning.setState(state);
        hxyjWarning.setDatechar(Timestamp.valueOf(LocalDateTime.now()));
        return hxyjWarningMapper.insert(hxyjWarning);
    }

    @Override
    public Integer getMaxId() {
        HxyjWarning hxyjWarning = hxyjWarningMapper.selectOne(Wrappers.<HxyjWarning>lambdaQuery()
                .orderByDesc(HxyjWarning::getDocid)
                .last("limit 1"));
        return hxyjWarning == null ? 0 : hxyjWarning.getDocid();
    }

    @Override
    public Object creatProduct(Integer issueNum, String userName, String yjType, String sXType, String date, Integer nTimes, String colorAndPos, String posStr, MultipartFile[] images, String layerName, String dlData) throws ParseException, IOException {
        //模板路径
        String templatePath;
        //pdf路径
        String targetPdfPath = null;
        //产品路径
        String targetPath;

        ApplicationHome applicationHome = new ApplicationHome(this.getClass());
        if (active.equals("dev")) {
            templatePath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\Documents\\森林火险预报模板\\预警文档输出.docx";
            targetPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\temp\\森林火险预报.docx";
            targetPdfPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\temp\\森林火险预报.pdf";
        } else {
            templatePath = applicationHome.getSource().getParentFile() +
                    "\\resource\\Documents\\森林火险预报模板\\预警文档输出.docx";
            targetPath = applicationHome.getSource().getParentFile() +
                    "\\resources\\temp\\森林火险预报.docx";
            targetPdfPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\temp\\森林火险预报.pdf";
        }

        //json字符串转换为对象列表
        List<ColorAndPos> posList = JSON.parseArray(colorAndPos, ColorAndPos.class);
        //获取预警区内乡镇数据
        for (ColorAndPos typeAndPos : posList) {
            String type = typeAndPos.getColor();
            String color = "";
            switch (type) {
                case "0":
                    color = "黄色";
                    break;
                case "1":
                    color = "橙色";
                    break;
                case "2":
                    color = "红色";
                    break;
            }

            //多边形查询乡界面
            List<DmObj> map = getCountryMap(dmgisIp,dmgisPort,dmgisSerName,typeAndPos.getPos());

            //解析返回结果
            Map<Integer, List<ColorAndNameDto>> colorAndNameMap = getColorAndNameMap(type,color,map);

            //一级区县内容
            StringBuilder country1 = new StringBuilder();
            //二级区县内容
            StringBuilder country2 = new StringBuilder();
            //三级区县内容
            StringBuilder country3 = new StringBuilder();

            List<ColorAndNameDto> colorAndNameDtoListAll = new ArrayList<>();
            if (colorAndNameMap.containsKey(0)) {
                List<ColorAndNameDto> colorAndNameDtoList = colorAndNameMap.get(0);
                colorAndNameDtoListAll.addAll(colorAndNameDtoList);
                for (ColorAndNameDto colorAndNameDto : colorAndNameDtoList) {
                    country1.append(colorAndNameDto.getCountry()).append(",");
                }
                country1.deleteCharAt(country1.length() - 1);
            }
            if (colorAndNameMap.containsKey(1)) {
                List<ColorAndNameDto> colorAndNameDtoList = colorAndNameMap.get(1);
                colorAndNameDtoListAll.addAll(colorAndNameDtoList);
                for (ColorAndNameDto colorAndNameDto : colorAndNameDtoList) {
                    country2.append(colorAndNameDto.getCountry()).append(",");
                }
                country2.deleteCharAt(country2.length() - 1);

            }
            if (colorAndNameMap.containsKey(2)) {
                List<ColorAndNameDto> colorAndNameDtoList = colorAndNameMap.get(2);
                colorAndNameDtoListAll.addAll(colorAndNameDtoList);
                for (ColorAndNameDto colorAndNameDto : colorAndNameDtoList) {
                    country3.append(colorAndNameDto.getCountry()).append(",");
                }
                country3.deleteCharAt(country3.length() - 1);
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日HH时");
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
            SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy年MM月dd日");
            Date date1 = sdf.parse(date);
            //替换正文内容
            String timeChar = "";
            String timeStr1 = "";
            String timeStr2 = "";
            StringBuilder timeStr3 = new StringBuilder();
            StringBuilder waringResult = new StringBuilder();
            Calendar calendar1 = Calendar.getInstance();
            calendar1.setTime(date1);
            Calendar calendar2 = Calendar.getInstance();
            calendar2.setTime(date1);
            calendar2.add(Calendar.DATE, 1);
            Calendar nowCalendar = Calendar.getInstance();
            //设置日期范围
            if (nowCalendar.get(Calendar.HOUR_OF_DAY) > 12) {
                timeChar = "20";
                timeStr1 = sdf3.format(date1) + "20:00:00";
                timeStr2 = "今晚到明天";
                if (calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)
                        && calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH)) {
                    //年份月份都相同
                    timeStr3.append("自")
                            .append(calendar1.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar1.get(Calendar.DAY_OF_MONTH)).append("日20:00至")
                            .append(calendar2.get(Calendar.DAY_OF_MONTH)).append("日20:00");
                } else if (calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)) {
                    //年份相同
                    timeStr3.append("自")
                            .append(calendar1.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar1.get(Calendar.DAY_OF_MONTH)).append("日20:00至")
                            .append(calendar2.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar2.get(Calendar.DAY_OF_MONTH)).append("日20:00");
                } else {
                    //年份月份都不相同
                    timeStr3.append("自")
                            .append(calendar1.get(Calendar.YEAR)).append("年")
                            .append(calendar1.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar1.get(Calendar.DAY_OF_MONTH)).append("日20:00至")
                            .append(calendar2.get(Calendar.YEAR)).append("年")
                            .append(calendar2.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar2.get(Calendar.DAY_OF_MONTH)).append("日20:00");
                }
            } else {
                timeChar = "08";
                timeStr1 = sdf3.format(date1) + "08:00:00";
                timeStr2 = "今天白天到晚上";
                if (calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)
                        && calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH)) {
                    //年份月份都相同
                    timeStr3.append("自")
                            .append(calendar1.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar1.get(Calendar.DAY_OF_MONTH)).append("日08:00至")
                            .append(calendar2.get(Calendar.DAY_OF_MONTH)).append("日08:00");
                } else if (calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)) {
                    //年份相同
                    timeStr3.append("自")
                            .append(calendar1.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar1.get(Calendar.DAY_OF_MONTH)).append("日08:00至")
                            .append(calendar2.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar2.get(Calendar.DAY_OF_MONTH)).append("日08:00");
                } else {
                    //年份月份都不相同
                    timeStr3.append("自")
                            .append(calendar1.get(Calendar.YEAR)).append("年")
                            .append(calendar1.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar1.get(Calendar.DAY_OF_MONTH)).append("日08:00至")
                            .append(calendar2.get(Calendar.YEAR)).append("年")
                            .append(calendar2.get(Calendar.MONTH) + 1).append("月")
                            .append(calendar2.get(Calendar.DAY_OF_MONTH)).append("日08:00");
                }
            }
            if (country1.length() != 0) {
                waringResult.append("大部分区域发生火灾可能性较大（预报等级三级）");
            }
            if (country2.length() != 0) {
                waringResult.append("大部分区域发生火灾可能性大（预报等级四级）");
            }
            if (country3.length() != 0) {
                waringResult.append("其中部分地区发生火灾可能性很大（预报等级五）");
            }
//            waringResult.append(" \n ");
            if (country1.length() != 0) {
                waringResult.append("三级区域包括：").append(country1).append("等；");
            }
            if (country2.length() != 0) {
                waringResult.append("四级区域包括：").append(country2).append("等；");
            }
            if (country3.length() != 0) {
                waringResult.append("五级区域包括：").append(country3).append("等；");
            }

            //解析地理分析数据
            List<Object> layerObjectList = new ArrayList<>();
            if (StringUtils.isNotBlank(dlData) && StringUtils.isNotBlank(layerName)) {
                try {
                    List<LayerRcoDto> LayerRcoDtoList = JSON.parseArray(dlData, LayerRcoDto.class);
                    Class layerClass = getLayerClass(layerName);
                    for (LayerRcoDto layerRcoDto : LayerRcoDtoList) {
                        JSONObject rcoValObject = (JSONObject) layerRcoDto.getRcoValObject();
                        Object javaObject = JSON.toJavaObject(rcoValObject, layerClass);
                        layerObjectList.add(javaObject);
                    }
                } catch (Exception e) {
                    System.err.println("地理分析数据解析错误");
                }
            }

            //生成文档
            try (
                    InputStream templateInputStream = new FileInputStream(templatePath);
                    OutputStream targetOutputStream = new FileOutputStream(targetPath);
                    XWPFDocument document = new XWPFDocument(templateInputStream);
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    ByteArrayOutputStream byteArrayOutputStream1 = new ByteArrayOutputStream();
                    ByteArrayOutputStream byteArrayOutputStream2 = new ByteArrayOutputStream();
            ) {

                //段落替换
                String[] placeholders = new String[]{"[年份]", "[期数]", "[时间1]", "[时间3]", "[时间2]", "[预警情况]"};
                //替换内容
                String[] replacements = new String[]{String.valueOf(calendar1.get(Calendar.YEAR)),
                        String.valueOf(issueNum),
                        timeStr1,
                        timeStr2,
                        timeStr3.toString(),
                        waringResult.toString()};

                List<XWPFParagraph> paragraphs = document.getParagraphs();

                for (int i = 0; i < paragraphs.size(); i++) {
                    XWPFParagraph paragraph = paragraphs.get(i);
                    String text = paragraph.getText();
                    replaceTextInParagraph(paragraph, placeholders, replacements);
                    //插入图片
                    if (StringUtils.isNotBlank(text) && text.contains("[图片]")) {
                        //获取下标
                        XmlCursor cursor = paragraph.getCTP().newCursor();
                        XWPFParagraph newPara = document.insertNewParagraph(cursor);
                        newPara.setAlignment(ParagraphAlignment.CENTER);//居中
                        XWPFRun newParaRun = newPara.createRun();
                        for (MultipartFile image : images) {
                            //插入图片
                            newParaRun.addPicture(image.getInputStream(), XWPFDocument.PICTURE_TYPE_PNG, "image.png,", Units.toEMU(300), Units.toEMU(380));
                        }
                        document.removeBodyElement(document.getPosOfParagraph(paragraph));
                    }
                    //插入地理分析数据表格
                    if (layerObjectList.size() > 0 && StringUtils.isNotBlank(text) && text.contains("[分析数据]")) {
                        System.out.println("插入地理分析表格数据");
                            XWPFParagraph paragraph1 = document.createParagraph();
                            XWPFRun run = paragraph1.createRun();
                            run.setText(layerName+"分析");
                        //获取下标
                        XmlCursor cursor = paragraph.getCTP().newCursor();
                        XWPFTable table = document.insertNewTbl(cursor);
                        //插入图层表格数据
                        insertTablaLayerData(layerName, layerObjectList, table);
                        setTableLocation(table, "center");
                        setCellLocation(table, "CENTER", "center");
                        document.removeBodyElement(document.getPosOfParagraph(paragraph));

                    }
                }
                // 将生成的文档保存到输出文件
                document.write(targetOutputStream);

                //获取文档名称
                String productName = sdf3.format(date1) + "第" + issueNum + "期森林火险预报.docx";
                //插入森林火险预警表数据
                //设置预警内容
                HxyjWarning hxyjWarning = new HxyjWarning();
                hxyjWarning.setPos(posStr);
                hxyjWarning.setGradearea3(country1.toString());
                hxyjWarning.setGradearea4(country2.toString());
                hxyjWarning.setGradearea5(country3.toString());
                hxyjWarning.setWarn_result(waringResult.toString()+"森林火险气象等级较高，具体预报区域见附图。请各有关单位严加防范，确保林区安全。");
                hxyjWarning.setDatechar(sdf.parse(sdf2.format(date1)));
                hxyjWarning.setWarningtype(String.valueOf(nTimes));
                hxyjWarning.setState(3);
                hxyjWarning.setFirst(userName);
                hxyjWarning.setSecond(userName);
                hxyjWarning.setThird(userName);
                hxyjWarning.setIsrelease(0);
                hxyjWarning.setShflag(0);
                hxyjWarning.setDocpath(productName);
                hxyjWarningMapper.insert(hxyjWarning);
                //保存基本产品表数据
                BaseProduct baseProduct = new BaseProduct();
                baseProduct.setProductname(productName);
                baseProduct.setProducttype(yjType+sXType);
                baseProduct.setForecasttime(date1);
                baseProduct.setMaketime(new Date());
                baseProduct.setBindid(hxyjWarning.getDocid());
                baseProduct.setMaker(userName);
                baseProductMapper.insert(baseProduct);
                byte[] buffer = new byte[1024];
                int bytesRead;
                FileInputStream inputStream = new FileInputStream(targetPath);
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, bytesRead);
                }
                byte[] byteArray = byteArrayOutputStream.toByteArray();
                wordToPdf(targetPath, targetPdfPath);
//                //保存到mongodb库中
//                 HyDocFile hyDocFile = new HyDocFile();
//                 hyDocFile.setData(byteArray);
//                 hyDocFile.setTable_name("base_product");
//                 hyDocFile.setId(String.valueOf(baseProduct.getId()));
//                 mongoTemplate.save(hyDocFile);
                Map<String, Object> map1 = new HashMap<String, Object>();
                map1.put("id", String.valueOf(hxyjWarning.getDocid()));
                map1.put("data", byteArray);
                map1.put("table_name", "base_product");
                map1.put("collectionName", "doc_file");
                ms.insertData(map1);

                //pdf入库
                byte[] buffer1 = new byte[1024];
                int bytesRead1 ;
                FileInputStream inputStream1 = new FileInputStream(targetPdfPath);
                while ((bytesRead1 = inputStream1.read(buffer1)) != -1) {
                    byteArrayOutputStream1.write(buffer1, 0, bytesRead1);
                }

                byte[] bytes = byteArrayOutputStream1.toByteArray();
                Map<String, Object> map2 = new HashMap<String, Object>();
                map2.put("id", String.valueOf(hxyjWarning.getDocid()));
                map2.put("data", bytes);
                map2.put("table_name", "base_product");
                map2.put("collectionName", "pdf_file");
                map2.put("advCode", "451027");
                ms.insertData(map2);
                //图片
                for (MultipartFile image : images) {
                    //插入图片
                    InputStream inputStream2 = image.getInputStream();
                    byte[] buffer2 = new byte[1024];
                    int bytesRead2;
                    while ((bytesRead2 = inputStream2.read(buffer2)) != -1) {
                        byteArrayOutputStream2.write(buffer2, 0, bytesRead2);
                    }
                    byte[] bytes2 = byteArrayOutputStream2.toByteArray();
                    Map<String, Object> map3 = new HashMap<String, Object>();
                    map3.put("id", String.valueOf(baseProduct.getId()));
                    map3.put("data", bytes2);
                    map3.put("table_name", "base_product");
                    map3.put("collectionName", "image_file");
                    map3.put("advCode", "451027");
                    ms.insertData(map3);
                }
                // 设置前端响应
                HttpHeaders headers = new HttpHeaders();
                headers.setContentDispositionFormData("attachment", "森林火险预报文档.docx");
                headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                headers.setContentLength(byteArray.length);
//            wordToPdf(targetPath,targetPdfPath);
                return new ResponseEntity<>(byteArray, headers, HttpStatus.OK);
            } catch (Exception e) {
                e.printStackTrace();
                System.err.println("文档生成失败");
            }
        }
        return null;
    }
}
